<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>3D airport</title>
  <link rel="stylesheet" href="./css/inner.css">
</head>

<body>
  <div class="left-back">
    <a href="javascript:history.go(-1);" class="back-btn">返回上层</a>
  </div>
  <div id="WebGL-output"></div>
  <script src="js/three.js"></script>
  <script src="js/OrbitControls.js"></script>
  <script src="js/DDSLoader.js"></script>
  <script src="js/OBJLoader.js"></script>
  <script src="js/MTLLoader.js"></script>
  <script src="js/stats.min.js"></script>
  <script>
    var stats
    var scene, camera, renderer
    var raycaster = new THREE.Raycaster()
    var mouse = new THREE.Vector2()

    // ===============  开启帧数检测 ======================
    function initStats() {
      stats = new Stats();
      stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
      stats.dom.style.position = 'absolute';
      stats.dom.style.right = '0px';
      stats.dom.style.left = 'unset';
      stats.dom.style.top = '0px';
      document.body.appendChild(stats.dom);

      function animate() {
        stats.begin();
        stats.end();
        requestAnimationFrame(animate);
      }
      requestAnimationFrame(animate);
    }

    // ===========  初始化场景  ========================
    function initScene() {
      scene = new THREE.Scene(); //场景构建
      // 构建一个坐标轴
      // var axes = new THREE.AxisHelper(120);
      // scene.add(axes);
    }

    // =========== 渲染器构建 ========================
    function initRenderer() {
      renderer = new THREE.WebGLRenderer({
        antialias: true, // 抗锯齿
        alpha: true // 背景透明
      }); //渲染器构建
      renderer.setClearAlpha(0); // 透明度为0
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.shadowMapEnabled = true; //激活阴影
      document.querySelector("#WebGL-output").append(renderer.domElement)
    }

    // ===============  初始化摄像头 ================
    function initCamera() {
      camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000); //相机构建
      camera.position.x = 0;
      camera.position.y = 50;
      camera.position.z = 89;
      camera.lookAt(scene.position)
    }

    // ==================== 添加轨道控制器 =========================
    function initControl() {
      var orbitControls = new THREE.OrbitControls(camera, renderer.domElement);
      orbitControls.target = new THREE.Vector3(0, 0, 0) // 控制焦点
      orbitControls.autoRotate = false // 自动旋转关闭
      renderScene();

      function renderScene() {
        var clock = new THREE.Clock() // 用于更新轨道控制器
        var delta = clock.getDelta() // 获取时间差
        orbitControls.update(delta) // 更新时间
        requestAnimationFrame(renderScene);
      }
    }

    // ================== 灯光 =============================
    function initLights() {
      scene.add(new THREE.AmbientLight(0x0c0c0c));
      //添加材质灯光阴影
      var spotLight1 = new THREE.SpotLight(0xffffff);
      spotLight1.position.set(-150, 200, 0);
      scene.add(spotLight1);

      var spotLight2 = new THREE.SpotLight(0xffffff);
      spotLight2.position.set(150, 500, 0);
      scene.add(spotLight2);

      var spotLight3 = new THREE.SpotLight(0xffffff);
      spotLight3.position.set(150, 50, -200);
      scene.add(spotLight3);

      var spotLight4 = new THREE.SpotLight(0xffffff);
      spotLight4.position.set(150, 50, 200);
      scene.add(spotLight4);
    }

    // =================== model 加载 ================================
    function initFloor () {
      // 平面
      var geometry = new THREE.CubeGeometry(50, 0.1, 10);
      var material = new THREE.MeshBasicMaterial({
        color: 0xEEEEEE
      })
      var cube = new THREE.Mesh(geometry, material)
      cube.position.y = -0.1
      scene.add(cube)
      createAlarm()
      for (var i = 0; i < 3; i++) {
        var cube = new THREE.Mesh(geometry, material)
        cube.position.y = 10 * i
        createAlarm(0, 10*i, 0)
        scene.add(cube)
      }
      for (var i = 0; i < 3; i++) {
        var cube = new THREE.Mesh(geometry, material)
        cube.position.y = 10 * i
        cube.position.z = -15
        createAlarm(0, 10*i, -15)
        scene.add(cube)
      }
      for (var i = 0; i < 3; i++) {
        var cube = new THREE.Mesh(geometry, material)
        cube.position.y = 10 * i
        cube.position.z = -15
        cube.position.x = -60
        createAlarm(-60, 10*i, -15)
        scene.add(cube)
      }
      for (var i = 0; i < 3; i++) {
        var cube = new THREE.Mesh(geometry, material)
        cube.position.y = 10 * i
        cube.position.z = -15
        cube.position.x = 60
        createAlarm(60, 10*i, -15)
        scene.add(cube)
      }
      for (var i = 0; i < 3; i++) {
        var cube = new THREE.Mesh(geometry, material)
        cube.position.y = 10 * i
        cube.position.x = -60
        createAlarm(-60, 10*i, 0)
        scene.add(cube)
      }
      for (var i = 0; i < 3; i++) {
        var cube = new THREE.Mesh(geometry, material)
        cube.position.y = 10 * i
        cube.position.x = 60
        createAlarm(60, 10*i, 0)
        scene.add(cube)
      }
    }
    function createAlarm (x = 0, y = 0, z = 0) {
      var onProgress = function (xhr) {
        if (xhr.lengthComputable) {
          var percentComplete = xhr.loaded / xhr.total * 100;
        }
      };
      var onError = function (xhr) {};
      var mtlLoader = new THREE.MTLLoader();
      mtlLoader.setPath('objs/');
      // 感烟探测器
      mtlLoader.load('感烟探测器.mtl', function (materials) {
        materials.preload();
        var objLoader = new THREE.OBJLoader();
        objLoader.setMaterials(materials);
        objLoader.setPath('objs/');
        objLoader.load('感烟探测器.obj', function (object) {
          object.position.x = x;
          object.position.z = z;
          object.position.y = 5 + y;
          object.scale.set(0.05, 0.05, 0.05);
          object.name = '感烟探测器';
          scene.add(object);
        }, onProgress, onError);
      });
      // 灭火器
      mtlLoader.load('灭火器.mtl', function (materials) {
        materials.preload();
        var objLoader = new THREE.OBJLoader();
        objLoader.setMaterials(materials);
        objLoader.setPath('objs/');
        objLoader.load('灭火器.obj', function (object) {
          object.position.x = x;
          object.position.z = z;
          object.position.y = y;
          object.scale.set(0.05, 0.05, 0.05);
          object.name = '灭火器';
          scene.add(object);
        }, onProgress, onError);
      });
      // 声光报警器
      mtlLoader.load('声光报警器.mtl', function (materials) {
        materials.preload();
        var objLoader = new THREE.OBJLoader();
        objLoader.setMaterials(materials);
        objLoader.setPath('objs/');
        objLoader.load('声光报警器.obj', function (object) {
          object.position.x = 5 + x;
          object.position.z = z;
          object.position.y = y;
          object.scale.set(0.05, 0.05, 0.05);
          object.name = '声光报警器';
          scene.add(object);
        }, onProgress, onError);
      });
      // 手动报警按钮
      mtlLoader.load('手动报警按钮.mtl', function (materials) {
        materials.preload();
        var objLoader = new THREE.OBJLoader();
        objLoader.setMaterials(materials);
        objLoader.setPath('objs/');
        objLoader.load('手动报警按钮.obj', function (object) {
          object.position.x = 6 + x;
          object.position.z = z;
          object.position.y = y;
          object.scale.set(0.05, 0.05, 0.05);
          object.name = '手动报警按钮';
          scene.add(object);
        }, onProgress, onError);
      });
    }
    function initObjModel() {
      initFloor()
      var onProgress = function (xhr) {
        if (xhr.lengthComputable) {
          var percentComplete = xhr.loaded / xhr.total * 100
        }
      }
      var onError = function (xhr) {}
      var mtlLoader = new THREE.MTLLoader()
      mtlLoader.setPath('objs/')
      // 扶梯上行
      mtlLoader.load('扶梯上行.mtl', function (materials) {
        materials.preload()
        var objLoader = new THREE.OBJLoader()
        objLoader.setMaterials(materials)
        objLoader.setPath('objs/')
        objLoader.load('扶梯上行.obj', function (object) {
          object.position.x = 0
          object.position.z = 0
          object.position.y = 0
          // object.scale.set(0.05, 0.05, 0.05)
          object.scale.multiplyScalar(0.01)
          object.name = '扶梯上行'
          scene.add(object)
        }, onProgress, onError)
      })

      var tipsGeo1 = new THREE.PlaneBufferGeometry(30, 15, 1, 1)
			var tips1 = new THREE.Mesh(tipsGeo1, createFont('综合旅客服务', {bgColor: '#000', fontColor: '#46c2f3'}))
			tips1.position.set(-60, 0, 20)
			tips1.rotation.x = -89.52
			scene.add(tips1)

      var tipsGeo2 = new THREE.PlaneBufferGeometry(30, 15, 1, 1)
			var tips2 = new THREE.Mesh(tipsGeo2, createFont('国内航班进出港', {bgColor: '#000', fontColor: '#46c2f3'}))
			tips2.position.set(0, 0, 20)
			tips2.rotation.x = -89.52
			scene.add(tips2)

      var tipsGeo3 = new THREE.PlaneBufferGeometry(30, 15, 1, 1)
			var tips3 = new THREE.Mesh(tipsGeo3, createFont('国际航班进出港', {bgColor: '#000', fontColor: '#46c2f3'}))
			tips3.position.set(60, 0, 20)
			tips3.rotation.x = -89.52
			scene.add(tips3)
    }

		// ===================== 创建文字贴图 ======================
		/**
		 * text 文字
		 * options.fontColor 文字颜色
		 * options.bgColor 背景颜色
		 */
    function createFont (text, options={bgColor: '', fontColor: ''}) {
			var canvas = document.createElement("canvas");
			canvas.width = 512;
			canvas.height = 128;
			var c = canvas.getContext('2d');
			// 矩形区域填充背景
			c.fillStyle = options.bgColor || '#ff0000';
			c.fillRect(0, 0, 512, 128);
			c.beginPath();
			// 文字
			c.beginPath();
			c.translate(256,64);
			c.fillStyle = options.fontColor || '#ffffff'; //文本填充颜色
			c.font = '48px 微软雅黑'; //字体样式设置
			c.textBaseline = 'middle'; //文本与fillText定义的纵坐标
			c.textAlign = 'center'; //文本居中(以fillText定义的横坐标)
			c.fillText(text, 0, 0);
			var texture = new THREE.CanvasTexture(canvas);
			var textMaterial = new THREE.MeshPhongMaterial({
				map: texture, // 设置纹理贴图
				side: THREE.DoubleSide,
				transparent: true,
				opacity: 0.5
			});
			textMaterial.map.needsUpdate = true
			return textMaterial
		}
    // ===================== 方向键控制摄像头 =======================
    function initArrowKeydown() {
      document.addEventListener('keydown', handleKeyDown, false);

      function handleKeyDown(e) {
        var e = e || window.event;
        var keyCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
        if ('37, 38, 39, 40, 65, 87, 68, 83'.indexOf(keyCode) === -1) {
          return;
        } else {
          switch (e.keyCode) {
            case 37:
            case 65:
              CameraMove('x', -0.1);
              break;
            case 38:
            case 87:
              CameraMove('y', 0.1);
              break;
            case 39:
            case 68:
              CameraMove('x', 0.1);
              break;
            case 83:
            case 40:
              CameraMove('y', -0.1);
              break;
          }
        }
      }

      function CameraMove(direction, distance) {
        camera.position[direction] += distance;
      }
    }

    // ===================== 动画 ======================
    function initAnimate() {
      renderer.render(scene, camera)
      requestAnimationFrame(initAnimate)
    }

    // ===================== 等比缩放 ==========================
		function handleWindowResize() {
			camera.aspect = window.innerWidth / window.innerHeight
			camera.updateProjectionMatrix()
			renderer.setSize(window.innerWidth, window.innerHeight)
		}

    function initAll() {
      initStats()
      initScene()
      initRenderer()
      initCamera()
      initControl()
      initLights()
      initObjModel()
      initArrowKeydown()
      initAnimate()
      handleWindowResize()
      window.addEventListener('resize', handleWindowResize, false)
    }
    window.onload = function () {
      initAll()
    }
  </script>
</body>

</html>